<?php

/**
 * The static component to improve cake's cache system.
 * It will create static HTML file ready to serve without running PHP.
 * It is designed to handle many connnections at once without overloading the server.
 * 
 * It require to alter .htaccess file in root directory:
 * <pre><code>
 * &lt;IfModule mod_rewrite.c>
 *  RewriteEngine on
 *  RewriteCond /PATH/app/tmp/cache/static%{REQUEST_URI}.static -f
 *  RewriteRule ^(.*)$ /PATH/app/tmp/cache/static%{REQUEST_URI}.static [L]
 * 
 *  RewriteCond %{REQUEST_FILENAME} !-f
 *  RewriteRule    ^$ app/webroot/    [L]
 *  RewriteCond %{REQUEST_FILENAME} !-f
 *  RewriteRule    (.*) app/webroot/$1 [L]
 * &lt;/IfModule>
 * </code></pre>
 * <p>
 *  To use it, include component in controller. Use cake's cacheAction to config
 *  cache behavior (if enabled for action, cache duration etc).
 * </p>
 * <p><b>NOTE:</b> Once the view has been cached there is no other method than manually remove file to clear cache. You may use cron service to clear cache.</p>
 * @author Bartek <bartek@kalicinscy.com>, update: Paweł <pawel.psztyc@kalicinscy.com>
 * @copyright (c) 2012, Kalicińscy.com
 */
class StaticComponent extends Component {

    private $Controller;
    private $pathRoot;

    public function initialize(Controller $controller) {
        parent::initialize($controller);
        $this->pathRoot = CACHE . 'static';
        $this->Controller = &$controller;
    }
    
    /**
     * Cache current action.
     * No parametes is needed except output HTML.
     * All required parameters comming from controllers cacheAction property.
     * Configuration is the same as Cake's cache system.
     * @param string $html
     * @return type
     */
    public function create($html) {

        if (isset($this->Controller->request->params['nocache']) && $this->Controller->request->params['nocache'] == 1)
            return;
        $cacheTime = 0;
        if (is_array($this->Controller->cacheAction)) {
            $keys = array_keys($this->Controller->cacheAction);
            $index = null;

            foreach ($keys as $action) {
                if ($action == $this->Controller->params['action']) {
                    $index = $action;
                    break;
                }
            }

            if (!isset($index) && $this->Controller->action == 'index') {
                $index = 'index';
            }

            $options = $this->Controller->cacheAction;
            if (isset($this->Controller->cacheAction[$index])) {
                if (is_array($this->Controller->cacheAction[$index])) {
                    $options = array_merge(array('duration' => 0, 'callbacks' => false), $this->Controller->cacheAction[$index]);
                } else {
                    $cacheTime = $this->Controller->cacheAction[$index];
                }
            }
            if (isset($options['duration'])) {
                $cacheTime = $options['duration'];
            }
        } else {
            $cacheTime = $this->Controller->cacheAction;
        }

        $flash = CakeSession::read('Message.flash');
        $auth = CakeSession::read('Message.auth');

        if (!is_numeric($cacheTime)) {
            $cacheTime = strtotime($cacheTime);
        }
        //.json handlers don't like any additional data :(
        //$html .= '<!-- cache expire:' . $cacheTime . ' -->';
        if ($cacheTime != '' && $cacheTime > 0 && empty($flash) && empty($auth)) {
            $path = $this->pathRoot . str_replace(" ", "+", $this->Controller->here) . '.static';
            if (strpos($path, "..") !== false)
                return;
            $dir = dirname($path);
            if (!file_exists($dir)) {
                mkdir($dir, 0775, true);
            }
            @file_put_contents($path, $html);
            @chmod($path, 0777);
        }
    }
    /**
     * Clear static cache folder.
     */
    public function clear() {
        App::uses('Folder', 'Utility');
        App::uses('File', 'Utility');
        $folder = new Folder($this->pathRoot, true);
        $contents = $folder->read(false, false, true);
        $folders = $contents[0];
        $files = $contents[1];

        foreach ($folders as $_folder) {
            $handler = new Folder($_folder, true);
            if (!$handler->delete()) {
                $this->log('Unable delete directory: ' . $_folder, 'error');
            }
        }

        foreach ($files as $file) {
            if (strpos($file, '.htaccess') !== false)
                continue;
            $handler = new File($file);
            if (!$handler->delete()) {
                $this->log('Unable delete file: ' . $file, 'error');
            }
        }
    }

}

?>